# -*_ coding:utf-8 _*_

"""

操作串口的主服务程序

@author: HXP
@date:2018-1-12
"""
import array
import gzip
import struct
import threading
import time
import traceback
import serial
import message_type
import general_action
from json_parse import parse_action
from voice_action import face_action

json_str = '{"type": "tts","content": {"action": "start", "text": "好的"}}'


class COMThread(threading.Thread):
    def __init__(self, name='COMThread'):  # 初始化线程
        threading.Thread.__init__(self, name=name)
        self.stopevent = threading.Event()
        self.stopevent.clear()
        self.msg_ID = 0

        # 将串口定义为"/dev/xunfei，比特率为115200，超时0.5秒"  /dev/ttyUSB0
        self.ser = serial.Serial(port='/dev/ttyUSB1', baudrate=115200, timeout=0.5)
        if self.ser is None:
            print('无法打开串口')

    # 获取消息长度
    @staticmethod
    def get_msg_len(data):
        return (data[3]) + ((data[4]) << 8)

    # 获取消息ID
    @staticmethod
    def get_msg_id(data):
        return (data[5]) + ((data[6]) << 8)

    # 向串口发送确认消息
    def send_ok(self, data, msg_type):
        ok_msg = array.array('B', [0xA5, 0x01, msg_type, 0x04, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x00])
        if data is None:
            self.msg_ID += 1
            if self.msg_ID > 65535:
                self.msg_ID = 0
            ok_msg[5] = self.msg_ID & 0xff
            ok_msg[6] = (self.msg_ID >> 8) & 0xff
        else:
            ok_msg[5] = (data[5])  # 设置消息ID
            ok_msg[6] = (data[6])
        ok_msg[11] = (~sum(ok_msg) + 1) & 0xff
        # print(ok_msg)
        self.ser.write(ok_msg)

    # 向串口发送消息
    def send_message(self, data, text, msg_type):
        # 第0——2位：同步头、用户ID、消息类型
        send_data = array.array('B', [0xA5, 0x01, msg_type])
        msg = text.encode('utf-8')
        # 第3——4位是消息长度
        msg_len = len(msg)
        send_data.extend(struct.pack('<H', msg_len))
        # 第5——6位是消息ID
        send_data.extend(data[4:6])
        # 第7——m位是消息主题
        send_data.extend(msg)
        # 第m+1位为校验位
        send_data.append((~sum(send_data) + 1) & 0xff)
        print(send_data)
        # 最后发送消息
        self.ser.write(send_data)

    # 解析AIUI消息
    def parse_msg(self, flag, data):
        print('msgType=%d' % (flag[2]))  # 打印出消息类型
        # 判断消息类型
        if flag[2] == message_type.AIUI_MSG:  # AIUI消息
            #           buf=StringIO(data)
            d = gzip.decompress(data)  # gzip解压
            json_data = d.decode('utf-8')  # utf-8解码
            # 如果是动作指令
            text = parse_action(json_data)
            print(json_data)
            if text is not None:
                if isinstance(text, str):
                    print('开始发音')
                    # 创建嘴部动作线程
                    t = threading.Thread(target=face_action, name='Thread-Face', args=(text,))
                    t.start()
                    t.join()
                else:
                    face_action('好的')  # 嘴部动作
                    for position in text:
                        self.send_message(flag, json_str, message_type.CTRL_MSG)
                        general_action.take_general_action(position)
                        time.sleep(0.5)

    def run(self):
        if self.ser is None:
            return
        # self.ser.open()  # 开起串口
        print("%s starts" % (self.getName()))

        while not self.stopevent.isSet():
            try:
                flag_read = self.ser.read()  # 读取串口数据，一个字节
                if len(flag_read) > 0:  # 如果获取到数据
                    flag_read += self.ser.read(6)  # 读到第六个字节，flag_read[0-6]
                    if flag_read[0] == 165:  # 接收到数据 , flag is 0xA5 ,165（同步头）
                        data_len = self.get_msg_len(flag_read)  # 接收到的数据长度
                        if 0 < data_len < 1024 * 1024:
                            data_read = self.ser.read(data_len)  # 读串口消息数据
                            self.ser.read()  # 读最后一个字节的校验码
                            self.send_ok(flag_read, message_type.OK_MSG)  # 向串口发送确认消息
                            self.parse_msg(flag_read, data_read)  # 解析收到的消息
                            self.send_ok(flag_read, message_type.OK_MSG)
                            print('get one msg len=%d' % data_len)  # 打印消息长度
                            print(flag_read+data_read)
            except serial.SerialException:
                print('serial.SerialException ERROR')
                print(traceback.format_exc())
                continue
        self.ser.close()  # 串口关闭
        print("%s ends" % (self.getName()))

    # 关闭串口线程
    def stop(self, timeout=None):
        self.stopevent.set()
        print("COMThread.join()")
        threading.Thread.join(self, timeout)


if __name__ == "__main__":
    try:
        th1 = COMThread()
        th1.start()
        time.sleep(60)
        # th1.stop()
    except:
        pass
